package mdp.solve;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;

import dd.discrete.DD;

import util.Pair;
import util.Timer;
import mdp.id.ADDHandler;
import mdp.id.RDDL2DD;
import mdp.id.RDDL2DD.DEBUG;
import mdp.id.RDDL2DD.ORDER;

public class PolicyIterationConcurrent<T extends RDDL2DD> implements Runnable {

        private T _handler;
        private ArrayBlockingQueue<Pair<T, Integer>> _bq = null;
        private int evalLength = 0;
        /**
         * 
         */
        public PolicyIterationConcurrent(T handler, String domain, String instance, 
                        ArrayBlockingQueue<Pair<T, Integer>> bq, int evallen) {
                _bq = bq;
                _handler = handler;
                _handler.buildFromFile(domain, instance);
                evalLength = evallen;
        }
        
        public void run() {
                
                int iter = 0;
                int pi = _handler.getInitialPolicy();
                int pid = -1;
                boolean done = false;
                Pair<Integer, Integer> vq = new Pair<Integer, Integer>(_handler.DD_ZERO, _handler.DD_ZERO);
                Timer solutionTimer = new Timer(); 
                
                while( !done ){
                		solutionTimer.ResumeTimer();
                		
                		int v = _handler.evaluatePolicy(pi, evalLength);
                		
                        
                        pid = _handler.improvePolicy(v, pi);
                        
                        ++iter;

                        if( _handler._debug.compareTo(DEBUG.SOLUTION_INFO) >= 0 ){
                                System.out.println("Size of policy " + _handler.getSize(pid));
                        }
                        
                        _handler.forgetThis(pi);
                        if( pi == pid ){//|| _handler.isHorizon(iter) ){
                        	_handler.saveThis(vq._o1);
                            done = true;
                        }

//                        if( _handler._debug.compareTo(DEBUG.SOLUTION_INFO) >= 0 ){
//                                int d = _handler.makePolicy(vq._o1, vq._o2);
//                                _handler.setPolicyDD(d);
//                                System.out.println(_handler.playDD(d));
//                        }
                        
                        _handler.flushCaches(true, pid);
                        
                        pi = pid;
                        solutionTimer.PauseTimer();
                        System.out.println("iteration " + iter);
                }
                
                if( _bq != null ){
                    try {
//                            _bq.put(new Pair<T, Integer>(_handler, pi));
                    	int v = _handler.evaluatePolicy(pi, _handler.getHorizon());
                    	_bq.put(new Pair<T, Integer>(_handler, v));
                    } catch (InterruptedException e) {
                            e.printStackTrace();
                    }
                }
                
                solutionTimer.ResumeTimer();
                pi = _handler._context.applyInt(pi, _handler.DD_ONE, DD.ARITH_SUM);
                pi = _handler.fix(pi);
                pi = _handler.makePolicyHelper(pi, new HashMap<String, Boolean>());
                solutionTimer.PauseTimer();
                
//                _handler.showGraph(pid); 
//                _handler.showGraph(pi);
                _handler.setPolicyDD(pi);
                
                ArrayList stats = new ArrayList();
                try{
                	stats = _handler.playDD(pi);
                }catch(Exception e) {
                	e.printStackTrace();
                }
                
                stats.add(0);
                stats.add(solutionTimer.GetElapsedTimeInMinutes());
                stats.add(0);
                stats.add(_handler.getSize(pi));
                
                System.out.println(stats);
                
               
                
        }

        public static void main(String[] args) throws InterruptedException {
                ADDHandler handle = new ADDHandler(DEBUG.PROBLEM_INFO , ORDER.GUESS);
                Runnable pic = 
                        new PolicyIterationConcurrent<ADDHandler>(handle, args[0], args[1], null, Integer.parseInt(args[2]));
                
                Thread picWorker = new Thread(pic, "PIC");
                picWorker.start();
                picWorker.join();
        }
}
